const fs = require("fs");
const path = require("path");
const axios = require("axios");
const cheerio = require("cheerio");
const { promisify } = require("util");

const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const mkdir = promisify(fs.mkdir);
const exists = promisify(fs.exists);

// 配置
const inputFile = "posts.json";
const outputFile = "newPosts.json";
const failedFile = "failed-images.txt";
const imagesDir = path.join(__dirname, "images");
const throttleDelay = 500;
const maxConcurrency = 5;

async function ensureImagesFolder() {
  if (!(await exists(imagesDir))) {
    await mkdir(imagesDir);
    console.log("📁 已创建 images 文件夹");
  }
}

async function downloadImage(url, filename) {
  try {
    const res = await axios.get(url, {
      responseType: "arraybuffer",
      timeout: 15000,
    });
    const filePath = path.join(imagesDir, filename);
    await writeFile(filePath, res.data);
    return true;
  } catch (error) {
    return false;
  }
}

function extractImageUrls(bodyHtml) {
  const $ = cheerio.load(bodyHtml);
  const urls = [];
  $("img").each((_, img) => {
    const src = $(img).attr("src");
    if (src) urls.push(src);
  });
  return urls;
}

async function processPosts() {
  try {
    const rawData = await readFile(inputFile, "utf8");
    const posts = JSON.parse(rawData);
    if (!Array.isArray(posts)) throw new Error("posts.json 格式错误，应为数组");

    await ensureImagesFolder();

    const urlMap = new Map();
    let imgIndex = 0;

    for (const post of posts) {
      const body = post.Body || "";
      const urls = extractImageUrls(body);
      for (const url of urls) {
        if (!urlMap.has(url)) {
          const ext = path.extname(url).split("?")[0] || ".jpg";
          const filename = `img_${imgIndex++}${ext}`;
          urlMap.set(url, filename);
        }
      }
    }

    console.log(`🔍 共提取图片 ${urlMap.size} 张`);

    const urlEntries = Array.from(urlMap.entries());
    let successCount = 0;
    let failedCount = 0;
    let currentIndex = 0;
    const failedUrls = [];

    async function worker(workerId) {
      while (currentIndex < urlEntries.length) {
        const index = currentIndex++;
        const [url, filename] = urlEntries[index];

        await new Promise((r) => setTimeout(r, throttleDelay));

        const ok = await downloadImage(url, filename);
        if (ok) {
          successCount++;
        } else {
          failedCount++;
          urlMap.delete(url);
          failedUrls.push(url); // 收集失败链接
        }

        console.log(
          `[#${workerId}] 进度 ${successCount + failedCount}/${
            urlEntries.length
          }`
        );
      }
    }

    const workers = Array.from({ length: maxConcurrency }, (_, i) =>
      worker(i + 1)
    );
    await Promise.all(workers);

    console.log(`✅ 图片下载完成：成功 ${successCount}，失败 ${failedCount}`);

    // 记录失败的链接
    if (failedUrls.length > 0) {
      const content = failedUrls.map((url, i) => `${i + 1}. ${url}`).join("\n");
      await writeFile(failedFile, content, "utf8");
      console.log(`⚠️ 已保存失败链接到 ${failedFile}`);
    }

    // 替换 HTML 中的图片地址
    for (const post of posts) {
      let html = post.Body || "";
      const $ = cheerio.load(html);
      $("img").each((_, img) => {
        const src = $(img).attr("src");
        const filename = urlMap.get(src);
        if (filename) {
          $(img).attr("src", `/images/${filename}`);
        }
      });
      post.Body = $.html();
    }

    await writeFile(outputFile, JSON.stringify(posts, null, 2), "utf8");
    console.log(`🎉 已生成新文件 ${outputFile}`);
  } catch (err) {
    console.error("❌ 程序出错：", err.message);
  }
}

processPosts();
